package club.itstudio.itouc.service.schedule

import club.itstudio.itouc.config.ElectiveCoursecConfig
import club.itstudio.itouc.core.annotation.ReqMap
import club.itstudio.itouc.core.exception.ConnectFailure
import club.itstudio.itouc.core.util.logger
import club.itstudio.itouc.entity.Course
import club.itstudio.itouc.entity.CourseType
import club.itstudio.itouc.entity.JwSession
import club.itstudio.itouc.jw.ParamsBuilder
import club.itstudio.itouc.jw.Parser
import club.itstudio.itouc.jw.with
import club.itstudio.itouc.service.JwOps
import club.itstudio.itouc.util.Mysql
import club.itstudio.itouc.util.Redis
import club.itstudio.itouc.service.TaskLockService
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service

/**
 * 定时更新课程数据
 */
@Service
class UpdateCourseService(val taskLockService: TaskLockService,
                          val jwOps: JwOps,
                          val jw: ParamsBuilder,
                          val ecConfig: ElectiveCoursecConfig,
                          val redis: Redis,
                          val mysql: Mysql,
                          val parser: Parser){

    val logger = logger()

    var session = JwSession("17020031002", "chen1234", timestamp = -1L).also {
        redis.saveJwSession(it)
    }

    /**
     * 更新专业课
     */
    fun updateSpecialty() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Specialty.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新专业课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                val gradeRange = jwOps.electiveGradeRange()
                val year = ecConfig.year
                val semester = ecConfig.semester
                gradeRange.forEach {
                    val grade = it.toString()
                    waitUtilNoReq()
                    val specialtyList = jwOps.getSpecialtyList(grade)
                    specialtyList.forEach {specialty ->
                        val data = try {
                            waitUtilNoReq()
                            jw.specialtyCourseList(grade, specialty.code, year, semester) with jwSession
                        }catch (e: ConnectFailure) {
                            try {
                                waitUtilNoReq()
                                jw.specialtyCourseList(grade, specialty.code, year, semester) with jwSession
                            }catch (e: ConnectFailure) {
                                waitUtilNoReq()
                                jw.specialtyCourseList(grade, specialty.code, year, semester) with jwSession
                            }
                        }
                        val courseType = "${CourseType.Specialty.name}-$grade-${specialty.code}"
                        saveCourse(parser.courseList(listOf(data), courseType))
                    }
                }
            }finally {
                taskLockService.deleteLock(taskName)
            }
            logger.info("更新专业课完毕")
        }
    }

    /**
     * 更新公共基础课
     */
    fun updatePublic(){
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Public.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新公共基础课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.publicClassList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.publicClassList(page, year = ecConfig.year, semester = ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.publicClassList(page, year = ecConfig.year, semester = ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Public.name))
            }catch (e: Exception) {
                logger.error("更新公共课失败", e.toString())
            }finally {
                taskLockService.deleteLock(taskName)
            }
            logger.info("更新公共基础课完毕")
        }
    }

    /**
     * 更新通识课
     */
    fun updateCommon(){
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Common.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新通识课")
                val year = ecConfig.year
                val semester = ecConfig.semester
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.commonClassList(year = year, semester = semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.commonClassList(page, year, semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.commonClassList(page, year, semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Common.name))
                logger.info("更新通识课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新思政军事课
     */
    fun updatePolity() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Polity.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新思政军事课")
                val year = ecConfig.year
                val semester = ecConfig.semester
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                var data = jw.polityCourseList(year = year, semester = semester) with jwSession
                var pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    waitUtilNoReq()
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.polityCourseList(page, year, semester) with jwSession)
                    }catch (e: Exception){
                        waitUtilNoReq()
                        dataList.add(jw.polityCourseList(page, year, semester) with jwSession)
                    }
                }
                waitUtilNoReq()
                data = jw.militaryCourseList(year = year, semester = semester) with jwSession
                pageNumber = parser.getTotalPage(data)
                dataList.add(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.militaryCourseList(page, year, semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.militaryCourseList(page, year, semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Polity.name))
                logger.info("更新思政军事课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新体育课
     */
    fun updatePE() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.PE.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新体育课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.peCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.peCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.peCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.PE.name))
                logger.info("更新体育课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新英语课
     */
    fun updateEnglish() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.AdvancedEnglish.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新英语课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.englishCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.englishCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.englishCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.AdvancedEnglish.name))
                logger.info("更新英语课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新物理课
     */
    fun updatePhysics() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Physics.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新物理课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.physicsCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.physicsCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.physicsCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Physics.name))
                logger.info("更新物理课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新化学课
     */
    fun updateChemistry() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Chemistry.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新化学课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.chemistryCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.chemistryCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.chemistryCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Chemistry.name))
                logger.info("更新化学课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新数学课
     */
    fun updateMath() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.Math.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新数学课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.mathCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.mathCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.mathCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.Math.name))
                logger.info("更新数学课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    /**
     * 更新计算机基础课
     */
    fun updateBasicComputer() {
        val expire = System.currentTimeMillis() + 5 * 60 * 1000
        val taskName = CourseType.BasicComputer.type
        if (taskLockService.getLock(taskName, expire)) {
            try {
                logger.info("开始更新计算机基础课")
                waitUtilNoReq()
                val jwSession = jwOps.getValidJwSession(session.token)
                waitUtilNoReq()
                val data = jw.basicComputerCourseList(year = ecConfig.year, semester = ecConfig.semester) with jwSession
                val pageNumber = parser.getTotalPage(data)
                val dataList = mutableListOf(data)
                for (page in 2..pageNumber) {
                    try {
                        waitUtilNoReq()
                        dataList.add(jw.basicComputerCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }catch (e: Exception) {
                        waitUtilNoReq()
                        dataList.add(jw.basicComputerCourseList(page, ecConfig.year, ecConfig.semester) with jwSession)
                    }
                }
                saveCourse(parser.courseList(dataList, CourseType.BasicComputer.name))
                logger.info("更新计算机基础课完毕")
            }finally {
                taskLockService.deleteLock(taskName)
            }
        }
    }

    fun saveCourse(courseList: List<Course>) {
        redis.saveCourseList(courseList)
        mysql.saveCourseList(courseList)
    }

    /**
     * 选课时期更新频率高
     */
    @Scheduled(cron = "45 0,8,16,24,32,40,48,54 * * * ? ")
    fun updateCourseSchedule() {
        if (ecConfig.refresh) {
            updatePublic()
            updateSpecialty()
            updateCommon()
            updateMath()
            updateEnglish()
            updatePE()
            updatePolity()
            updateBasicComputer()
            updatePhysics()
            updateChemistry()
        }
    }

    /**
     * 非选课时期一日一更新
     */
    @Scheduled(cron = "0 0 3 * * ? ")
    fun updateCourseEveryDay() {
        if (!ecConfig.refresh) {
            updatePublic()
            updateSpecialty()
            updateCommon()
            updateMath()
            updateEnglish()
            updatePE()
            updatePolity()
            updateBasicComputer()
            updatePhysics()
            updateChemistry()
        }
    }

    // 等待直到请求为0
    fun waitUtilNoReq() {
        while (ReqMap.size > 0) {
            Thread.sleep(1000 )
        }
    }

}